import json
import logging
from decimal import Decimal, InvalidOperation

from django.db import connection, transaction

from app.my_exception import MyException
from app.service import stock, member, goods, app_order, app_api
from app.service.ali import Ali
from app.service.wx import WxPay
from libs import common, time_helper
from libs.common import rand_str, get_ts
from libs.db import DB
from libs.time_helper import mts_to_time_str

logger = logging.getLogger(__name__)

PaymentMethodDict = {1: '现金', 2: '仓储卡', 3: '余额', 10: '线下扫码', 100: '微信/支付宝',200:'快餐店会员账户'}

OrderStatusDict = {-100: '已反结账', -5: '无单退换货', -3: '支付失败', -2: '退货子单', -1: '已退货', 0: '未结', 1: '已结'}


# 生成订单编号
def gen_order_sn(cart_cat=0):
    time_str = mts_to_time_str()
    rs = rand_str(5, 2)
    return '{}{}{}'.format(time_str, cart_cat, rs)


# 处理仓储卡支付 2 扣除（默认reduce）/添加(add) 会员表storage
# payment_amount_dec 需为Decimal类型
def process_member_storage_fund(cursor, mem_data, payment_amount_dec, flag='reduce'):
    err = None
    try:
        use_storage_pay_amount = payment_amount_dec  # 使用会员仓储卡支付
        db_mem_storage = mem_data.get('storage', 0)
        db_mem_storage_dec = Decimal(db_mem_storage)
        db_mem_id = mem_data.get('id', 0)
        if db_mem_storage_dec < use_storage_pay_amount:
            return '会员仓储卡（{}）不足'.format(db_mem_storage)
        db_mem_username = mem_data.get('username', '')
        db_mem_user_level = mem_data.get('user_level', 0)
        db_mem_ver = mem_data.get('ver')
        balance_data = {
            'PaymentMethod': 2,
            'member_id': db_mem_id,
            'username': db_mem_username,
            'storage': db_mem_storage,
            'user_level': db_mem_user_level,
            'pay_amount': use_storage_pay_amount,
            'ver': db_mem_ver
        }
        _, update_err = member.record_mem_funds_changed(cursor, balance_data, flag)
        if update_err is not None:
            return update_err
    except InvalidOperation:
        err = '无效的仓储卡金额'
    return err


# 处理会员余额支付 3 扣除会员表usdt_value
def process_member_balance_fund(cursor, mem_data, payment_amount_dec, flag='reduce'):
    err = None
    try:
        use_balance_pay_amount = payment_amount_dec  # 使用会员余额支付
        db_mem_balance = mem_data.get('usdt_value', 0)
        db_mem_balance_dec = Decimal(db_mem_balance)
        db_mem_id = mem_data.get('id', 0)
        if db_mem_balance_dec < use_balance_pay_amount:
            return '会员余额（{}）不足'.format(db_mem_balance)
        db_mem_username = mem_data.get('username', '')
        db_mem_user_level = mem_data.get('user_level', 0)
        db_mem_ver = mem_data.get('ver')
        balance_data = {
            'PaymentMethod': 3,
            'member_id': db_mem_id,
            'username': db_mem_username,
            'usdt_value': db_mem_balance,
            'user_level': db_mem_user_level,
            'pay_amount': use_balance_pay_amount,
            'ver': db_mem_ver
        }
        _, update_err = member.record_mem_funds_changed(cursor, balance_data, flag)
        if update_err is not None:
            return update_err
    except InvalidOperation:
        err = '无效的余额支付金额'
    return err

# 处理会员快餐店账户支付 4 扣除会员表fast_ballance
def process_fast_balance_fund(cursor, mem_data, payment_amount_dec, flag='reduce'):
    err = None
    try:
        use_balance_pay_amount = payment_amount_dec  # 使用会员快餐店账户
        db_mem_balance = mem_data.get('fast_ballance', 0)
        db_mem_balance_dec = Decimal(db_mem_balance)
        db_mem_id = mem_data.get('id', 0)
        if flag == 'reduce' and db_mem_balance_dec < use_balance_pay_amount:
            return '会员快餐店账户（{}）不足'.format(db_mem_balance)
        db_mem_username = mem_data.get('username', '')
        db_mem_user_level = mem_data.get('user_level', 0)
        db_mem_ver = mem_data.get('ver')
        balance_data = {
            'member_id': db_mem_id,
            'username': db_mem_username,
            'fast_ballance': db_mem_balance,
            'user_level': db_mem_user_level,
            'pay_amount': use_balance_pay_amount,
            'ver': db_mem_ver
        }
        _, update_err = member.record_mem_fast_changed(cursor, balance_data, flag)
        if update_err is not None:
            return update_err
    except InvalidOperation:
        err = '无效的快餐店账户支付金额'
    return err

# 处理线下扫码支付 10
def process_scan_payment():
    print('处理微信/支付宝支付')
    err = None
    return err


# 处理微信/支付宝支付 100
def process_wx_or_ali_payment():
    print('处理微信/支付宝支付')
    err = None
    return err


def get_pay_method_by_typ(typ, third_party_flag):
    # 仓储卡是table_member表storage
    # 余额是table_member表usdt_value
    typ_name = PaymentMethodDict.get(typ, '未知')
    if typ == 100:
        if third_party_flag == 1:
            typ_name = '微信'
        elif third_party_flag == 2:
            typ_name = '支付宝'
    return typ_name


# 保存单条订单支付日志
def save_order_pay_log(log_data: dict, cursor=None):
    log_id = 0
    order_id = log_data.get('order_id', 0)
    if order_id <= 0:
        err = '无效的订单ID'
        return log_id, err
    now = get_ts()
    log_data.update({'created': now, 'updated': now})
    db = DB('cs_order_pay_logs', conn=cursor)
    log_id, err = db.insert(log_data)
    return log_id, err


# 保存多条订单支付日志
def save_order_pay_logs(cashier_id, order_id, pay_method_dic: dict, cursor=None):
    err = None
    log_id_dict = {}
    for pay_method_typ in pay_method_dic:
        pay_data = pay_method_dic.get(pay_method_typ, {})
        pay_amount = pay_data.get('pay_amount', 0)
        confirmed = pay_data.get('confirmed', 0)
        third_party_pay_flag = pay_data.get('third_party_pay_flag', 0)
        tp_status = 0
        if confirmed > 0:
            tp_status = 1
        order_pay_log = {
            'cashier_id': cashier_id,
            'order_id': order_id,
            'pay_method_typ': pay_method_typ,
            'pay_method': get_pay_method_by_typ(pay_method_typ, third_party_pay_flag),
            'pay_typ_id': third_party_pay_flag,
            'pay_amount': str(pay_amount),
            'confirmed': confirmed,
            'tp_status': tp_status,
        }
        log_id, err = save_order_pay_log(order_pay_log, cursor)
        if err is not None:
            return log_id_dict, err
        log_id_dict[pay_method_typ] = log_id
    return log_id_dict, err


def insert_order(cursor, order_bindings):
    insert_order_sql = 'insert into cs_orders ' \
                       '(shop_id,cashier_id,order_sn,bill_num,pay_method,' \
                       'member_id,account,goods_num,total_price,cart_total_price,' \
                       'status,created,updated,deal_type,meal_number,is_quick) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
    cursor.execute(insert_order_sql, order_bindings)
    return cursor.lastrowid


def get_order_by_id(cursor, order_id, fields=None):
    err = None
    if fields is None:
        fields = ['id', 'status']
    db = DB('cs_orders', conn=cursor)
    order_data = db.one(fields, {'id': order_id})
    db_order_id = order_data.get('id', 0)
    if not db_order_id > 0:
        err = '订单不存在'
    return order_data, err


# 检查订单是否可以反结账
def check_order_can_be_anti_settlement(cursor, order_id):
    fields = ['id', 'shop_id', 'cashier_id', 'order_sn', 'member_id', 'account', 'goods_num', 'status']
    order_data, err = get_order_by_id(cursor, order_id, fields)
    if err is not None:
        return order_data, err
    order_data_status = order_data.get('status')
    if order_data_status != 1:
        if order_data_status == -100:
            err = '当前订单状态已反结账，不可重复操作'
        else:
            order_status = OrderStatusDict.get(order_data_status, None)
            if order_status is None:
                err = '订单状态错误，无法继续执行'
            else:
                err = '当前订单状态“{}”，无法反结账'.format(order_status)
    return order_data, err


# 检查订单是否可以退货
def check_order_can_be_return(cursor, order_id):
    fields = ['id', 'shop_id', 'cashier_id', 'order_sn',
              'member_id', 'account', 'goods_num', 'total_price',
              'cart_total_price', 'status']
    order_data, err = get_order_by_id(cursor, order_id, fields)
    if err is not None:
        return order_data, err
    order_data_status = order_data.get('status')
    if order_data_status != 1:
        if order_data_status == -1:
            err = '当前订单状态已退货'
        else:
            order_status = OrderStatusDict.get(order_data_status, None)
            if order_status is None:
                err = '订单状态未知，无法完成退货'
            else:
                err = '当前订单状态“{}”，无法退货'.format(order_status)
    return order_data, err


# 获取整个订单商品列表
def get_order_goods_list(cursor, order_id):
    db = DB('cs_order_details', conn=cursor)
    fields = ['id', 'goods_id', 'goods_name', 'barcode', 'amount',
              'selling_price', 'is_input_price', 'is_discount', 'subtotal', 'is_half',
              'return_num', 'status','drink_type','drink_flavor','remark']
    return db.find(fields, {'order_id': order_id})


# 退货清单是否包含指定商品ID
def get_order_detail_item(input_order_detail_id, return_list: list):
    data = None
    for item in return_list:
        if input_order_detail_id == item.get('id'):
            data = item
            break
    return data


# 反还订单商品
def return_order_goods(cursor, order_id, shop_id, cashier_id, post_return_data=None):
    order_goods_list = get_order_goods_list(cursor, order_id)
    row_num = 0
    total_num = 0
    return_yuan = Decimal('0')  # 可退金额（订单详情商品状态正常的商品）
    pay_yuan = Decimal('0')  #
    result = {}
    return_order_detail_list = []  # 退货商品列表
    has_return_goods_list = False  # 是否存在退货列表
    if type(post_return_data) is list and len(post_return_data) > 0:
        # 未指定退货商品，反结账标记，整单退
        has_return_goods_list = True
    now = get_ts()
    for order_goods_data in order_goods_list:
        order_detail_id = order_goods_data.get('id')
        order_goods_id = order_goods_data.get('goods_id')
        order_goods_name = order_goods_data.get('goods_name')
        order_goods_num = order_goods_data.get('amount', 0)
        order_goods_is_half = order_goods_data.get('is_half')
        return_num = order_goods_num
        order_detail_new_status = -1  # 全部退货
        if has_return_goods_list:
            order_detail_new_status = -2  # 部分退货
            return_data = get_order_detail_item(order_detail_id, post_return_data)
            if return_data is not None:
                return_num = common.to_dec(return_data.get('num'))
                if return_num == 0:
                    continue
                elif not return_num <= order_goods_num:
                    err = '存在无效的退货数量' \
                          '，商品({})，购买数量{}' \
                          '，退货数量{}'.format(order_goods_name, order_goods_num, return_num)
                    return result, err
            else:
                # 订单列表里不存在，则执行下一条
                continue
        order_detail_id_str = str(order_detail_id)
        order_goods_selling_price = order_goods_data.get('selling_price')
        order_goods_subtotal = order_goods_data.get('subtotal')
        order_goods_status = order_goods_data.get('status')
        total_num += return_num
        row_num += 1
        return_num_str = str(return_num)
        return_num_dec = Decimal(return_num_str)
        if order_goods_is_half > 0:
            refund_subtotal, _ = common.calc_half_refund_amount(order_goods_num,
                                                                return_num,
                                                                order_goods_subtotal,
                                                                order_goods_is_half)
        else:
            refund_subtotal = (return_num_dec * order_goods_selling_price).quantize(Decimal('0.00'))
        if order_goods_status == 0:
            return_yuan += refund_subtotal
        pay_yuan += refund_subtotal
        stock_log_data = {
            'stock_order_id': order_id,
            'stock_typ': 11,
            'shop_id': shop_id,
            'cashier_id': cashier_id,
            'cash_device_code': '',
            'cost_price': order_goods_selling_price,
        }
        order_goods_data.update({'stock_prev': 0, 'stock_next': 0})
        # 更新商品库存
        if not order_goods_id == 0:
            updated_stock_log_data, err = stock.change_goods_stock(cursor, order_goods_id, return_num, stock_log_data)
            if err is not None:
                return result, err
            order_goods_data.update({
                'stock_prev': updated_stock_log_data.get('amount_prev'),
                'stock_next': updated_stock_log_data.get('amount_next')
            })
        order_goods_data.update({'return_num': return_num})
        return_order_detail_list.append(order_goods_data)

        update_data = {
            'status': order_detail_new_status,
            'updated': now,
            'return_num': return_num,
        }
        _, err = update_order_detail(cursor, order_detail_id_str, update_data)
        if err is not None:
            return result, err
    result = {
        'stats_data': {
            'row_num': row_num,
            'total_num': total_num,
            'return_yuan': return_yuan,
            'pay_yuan': pay_yuan,
        },
        'return_order_detail_list': return_order_detail_list,
    }
    return result, None


# 更新订单详情 
def update_order_detail(cursor, order_detail_id, update_data):
    db = DB('cs_order_details', conn=cursor)
    where_dict = {'id': order_detail_id}
    affected, err = db.update(update_data, where_dict)
    if err is not None:
        return err
    err = None
    if affected == 0:
        err = '更新订单详情状态失败'
    return affected, err


def update_order(cursor, shop_id, order_id, order_data):
    now = get_ts()
    db = DB('cs_orders', conn=cursor)
    update_data = {
        'updated': now,
    }
    update_data.update(order_data)
    affected, err = db.update(update_data, {'id': order_id, 'shop_id': shop_id})
    if err is not None:
        return err
    err = None
    if affected == 0:
        err = '更新订单状态失败'
    return err


# 保存退货单，更新商品库存，不受事务控制（因需要远程调用App接口）
def save_return_order(cursor, ori_order_data, app_order_data):
    new_cs_order_data = {}
    order_sn = gen_order_sn()
    now = get_ts()
    member_id = ori_order_data.get('member_id')
    account = ori_order_data.get('account')
    ori_cs_order_id = ori_order_data.get('id')
    ori_cs_order_sn = ori_order_data.get('order_sn')
    total_num = app_order_data.get('total_num')
    return_yuan = app_order_data.get('return_yuan')
    # 'id', 'shop_id', 'cashier_id', 'order_sn', 'member_id', 'account', 'goods_num', 'status'
    new_cs_order_data.update({
        'shop_id': ori_order_data.get('shop_id'),
        'cashier_id': ori_order_data.get('cashier_id'),
        'order_sn': order_sn,
        'bill_num': '',
        'pay_method': '',
        'member_id': member_id,
        'account': account,
        'goods_num': total_num,
        'return_num': total_num,
        'total_price': return_yuan,
        'cart_total_price': return_yuan,
        'assoc_order_id': ori_cs_order_id,
        'coupon_status': 1,
        'amount_sign': -1,
        'status': -2,
        'created': now,
        'updated': now,
    })
    dh = DB('cs_orders', conn=cursor)
    new_order_id, err = dh.insert(new_cs_order_data)
    if err is not None:
        return None, None, err
    if new_order_id == 0:
        return None, None, '保存退货单失败'
    new_cs_order_data.update({'id': new_order_id})
    datetime_str = time_helper.ts_to_time_str(time_format="%Y-%m-%d %H:%M:%S")
    ao_shop_id = app_order_data.get('shop_id')
    ao_shop_name = app_order_data.get('shop_name')
    pay_mode = app_order_data.get('pay_mode')
    only_pay_no = app_order_data.get('only_pay_no')
    new_app_order_data = {
        'order_id': order_sn,
        'member_id': account,
        'shoper_name': ao_shop_name,
        'order_time': datetime_str,
        'total': return_yuan,  # 订单总金额
        'pay_usdt': return_yuan,  # 支付金额
        'offline_order_id': order_sn,
        'cs_order_id': new_order_id,
        'is_mixed_pay': 0,
        'stats_total_price': 0,
        'pay_mode': pay_mode,
        'pay_time': datetime_str,
        'only_pay_no': only_pay_no,
        'send_shop_id': ao_shop_id,
        'state': 10
    }
    err = app_order.update_order_status_by_sn(cursor, ori_cs_order_sn, 12)
    if err is not None:
        return None, None, '更新App退货单状态失败'
    new_app_order_id, err = app_order.save_app_order(cursor, new_app_order_data)
    if new_app_order_id == 0 or err is not None:
        return None, None, '保存App退货单失败'
    new_app_order_data.update({'id': new_app_order_id})
    return new_cs_order_data, new_app_order_data, err


def save_return_order_detail(cursor, new_order_id, return_order_detail_list, app_order_data):
    err = None
    db = DB('cs_order_details', conn=cursor)
    now = get_ts()
    datetime_str = time_helper.ts_to_time_str(time_format="%Y-%m-%d %H:%M:%S")

    order_sn = app_order_data.get('order_sn')
    return_yuan = app_order_data.get('return_yuan')
    for return_order_detail in return_order_detail_list:
        return_num = return_order_detail.get('return_num')
        buy_amount = return_order_detail.get('amount')
        buy_subtotal = return_order_detail.get('subtotal')
        selling_price = return_order_detail.get('selling_price')
        is_half = return_order_detail.get('is_half')
        half_num_dec = 0
        if is_half > 0:
            subtotal, half_num_dec = common.calc_half_refund_amount(buy_amount, return_num, buy_subtotal,is_half)
        else:
            subtotal = (Decimal(str(return_num)) * selling_price).quantize(Decimal('0.00'))
        # 'id', 'goods_id', 'goods_name', 'barcode', 'amount',
        # 'selling_price', 'is_input_price', 'is_discount', 'subtotal', 'return_num', 'status'
        return_order_id = return_order_detail.get('id')
        return_order_goods_id = return_order_detail.get('goods_id')
        return_order_goods_name = return_order_detail.get('goods_name')
        new_order_detail_data = {
            'order_id': new_order_id,
            'goods_id': return_order_goods_id,
            'goods_name': return_order_goods_name,
            'amount': return_num,
            'is_half': is_half,
            'half_num': half_num_dec,
            'selling_price': selling_price,
            'is_input_price': return_order_detail.get('is_input_price'),
            'is_discount': return_order_detail.get('is_discount'),
            'subtotal': subtotal,
            'stock_prev': return_order_detail.get('stock_prev'),
            'stock_next': return_order_detail.get('stock_next'),
            'return_num': 0,
            'return_order_id': return_order_detail.get('id'),
            'status': -10,
            'created': now,
            'updated': now,
        }
        new_order_detail_id, err = db.insert(new_order_detail_data)
        if err is not None:
            return '记录退货明细失败【order_detail_id={}】'.format(return_order_id)
        stats_price = 0
        if return_yuan != 0:
            stats_price = subtotal / return_yuan
        account = app_order_data.get('account')
        shop_id = app_order_data.get('shop_id')
        shop_name = app_order_data.get('shop_name')
        pay_mode = app_order_data.get('pay_mode')
        only_pay_no = app_order_data.get('only_pay_no')
        new_app_order_detail_data = {
            'order_id': order_sn,
            'goods_id': return_order_goods_id,
            'member_id': account,
            'shoper_name': shop_name,
            'goods_name': return_order_goods_name,
            'goods_price': selling_price,
            'order_time': datetime_str,
            'ratio': 0,
            'sell_number': return_num,
            'is_discount_goods': 0,
            'sell_price': subtotal,
            'stats_price': stats_price,
            'state': 10,
            'pay_mode': pay_mode,
            'pay_usdt': subtotal,
            'only_pay_no': only_pay_no,
            'send_shop_id': shop_id,
        }
        app_order_detail_id, err = app_order.save_app_order_detail(cursor, new_app_order_detail_data)
        if app_order_detail_id == 0 or err is not None:
            return '记录App退货明细失败'
    return err


def get_order_pay_logs(cursor, order_id):
    db = DB('cs_order_pay_logs', conn=cursor)
    fields = ['id', 'order_id', 'pay_method_typ', 'pay_method',
              'pay_typ_id', 'pay_amount', 'confirmed', 'tp_order_sn', 'return_status']
    return db.find(fields, {'order_id': order_id})


# 退货订单退款
def return_order_refund(cursor, return_order, refund_amount_dec, cashier_id, return_order_id=0):
    order_id = return_order.get('id')
    member_id = return_order.get('member_id')
    pay_logs = get_order_pay_logs(cursor, order_id)
    if len(pay_logs) == 0:
        err = '缺少支付记录'
        return None, err
    to_member = None
    if member_id > 0:
        db_member = member.get_member_with_cursor(cursor, member_id)
        db_member_id = db_member.get('id')
        if db_member_id > 0:
            to_member = db_member
    pay_logs, err = batch_return_order_refund(cursor,
                                              to_member,
                                              return_order,
                                              pay_logs,
                                              refund_amount_dec,
                                              cashier_id,
                                              return_order_id)
    if err is None:
        refund_result = get_refund_result(pay_logs)
    else:
        refund_result = []
    return refund_result, err


def get_refund_result(pay_logs):
    refund_map = {}
    if pay_logs is not None:
        for pay_log in pay_logs:
            refund_typ = pay_log.get('refund_typ', 0)  # 退款方式
            if refund_typ > 0:
                refund_data = refund_map.get(refund_typ, None)
                pay_log_id = pay_log.get('id')
                pay_log_order_id = pay_log.get('order_id')
                pay_log_pay_method_typ = pay_log.get('pay_method_typ')
                pay_log_pay_method = pay_log.get('pay_method')
                pay_log_pay_typ_id = pay_log.get('pay_typ_id')
                pay_log_pay_amount = pay_log.get('pay_amount')
                new_pay_log = {
                    'id': pay_log_id,
                    'order_id': pay_log_order_id,
                    'pay_method_typ': pay_log_pay_method_typ,
                    'pay_method': pay_log_pay_method,
                    'pay_typ_id': pay_log_pay_typ_id,
                    'pay_amount': pay_log_pay_amount,
                }
                if refund_data is None:
                    refund_data = {
                        'refund_typ_name': PaymentMethodDict.get(refund_typ, '未知'),
                        'refund_typ': refund_typ,
                        'return_amount': pay_log.get('return_amount'),
                        'pay_data': [new_pay_log]
                    }
                    refund_map.update({refund_typ: refund_data})
                else:
                    return_amount = refund_data.get('return_amount') + Decimal(pay_log.get('return_amount'))
                    pay_data = refund_data.get('pay_data').append(new_pay_log)
                    refund_data.update({
                        'return_amount': return_amount,
                        'pay_data': pay_data
                    })
                    refund_map.update({refund_typ: refund_data})
    return list(refund_map.values())


# 排序退款
def sort_refund_payment_method(pay_logs):
    # 退款优先级 仓储卡->余额->线下扫码\现金->微信\支付宝
    sort_priority_level = [200,2, 3, 10, 1, 100]
    for i, pay_log in enumerate(pay_logs):
        if i > 0:
            a_pay_log = pay_logs[i - 1]
            a_pay_method_typ = a_pay_log.get('pay_method_typ')
            try:
                a_index = sort_priority_level.index(a_pay_method_typ)
            except Exception:
                a_index = 3
            b_pay_method_typ = pay_log.get('pay_method_typ')
            try:
                b_index = sort_priority_level.index(b_pay_method_typ)
            except Exception:
                b_index = 3
            if b_index < a_index:
                pay_logs[i - 1], pay_logs[i] = pay_logs[i], pay_logs[i - 1]
    return pay_logs


# 处理订单退款
def handle_order_refund(cursor, db_member, return_order, pay_log, refund_amount_dec):
    pay_method_typ = pay_log.get('pay_method_typ')
    refund_typ = pay_method_typ
    err = None
    if pay_method_typ == 1:  # 现金
        refund_typ = 1
    elif pay_method_typ == 2:  # 仓储卡， 退款到会员storage
        if db_member is None:
            logger.error('会员信息不存在，无法退还仓储卡。pay_log = %s', json.dumps(pay_log))
        else:
            refund_typ = 2
            err = process_member_storage_fund(cursor, db_member, refund_amount_dec, 'add')
    elif pay_method_typ == 3:  # 余额， 退款到会员usdt_value
        if db_member is None:
            logger.error('会员信息不存在，无法退还余额。pay_log = %s', json.dumps(pay_log))
        else:
            refund_typ = 3
            err = process_member_balance_fund(cursor, db_member, refund_amount_dec, 'add')
    elif pay_method_typ == 10:  # 线下扫码， 退款方式现金
        refund_typ = 1
    elif pay_method_typ == 100:  # 原路反还到微信
        pay_amount = pay_log.get('pay_amount')
        pay_typ_id = pay_log.get('pay_typ_id')
        if refund_amount_dec > pay_amount:
            return None, '退款金额超过支付金额'
        refund_fen = int(refund_amount_dec * Decimal('100'))
        pay_fen = int(pay_amount * Decimal('100'))
        order_sn = return_order.get('order_sn')
        if pay_typ_id == 1:  # 微信
            trade_no, _, err = WxPay().refund(pay_fen, refund_fen, order_sn, '订单退款')
        elif pay_typ_id == 2:  # 支付宝
            trade_no, _, err = Ali().refund(refund_fen, order_sn, '订单退款')
        else:
            return None, '无效的退款方式'
    elif pay_method_typ == 200:  # 快餐店会员账户余额
        if db_member is None:
            logger.error('会员信息不存在，无法退还快餐店会员账户余额。pay_log = %s', json.dumps(pay_log))
        else:
            refund_typ = 200
            err = process_fast_balance_fund(cursor, db_member, refund_amount_dec, 'add')
    else:
        err = '无效的退款方式'
    return refund_typ, err


# 批量处理订单退款
def batch_return_order_refund(cursor, db_member, return_order, pay_logs, refund_amount_dec, cashier_id,
                              return_order_id=0):
    pay_logs = sort_refund_payment_method(pay_logs)
    err = None
    member_fund_update_counter = 0
    refund_flag = False
    now = get_ts()
    for i, pay_log in enumerate(pay_logs):
        pay_log_id = pay_log.get('id')
        log_return_status = pay_log.get('return_status')
        if log_return_status == 1:
            return None, '存在已退款记录，请核对订单'
        pay_amount = pay_log.get('pay_amount')
        if pay_amount <= refund_amount_dec:  # 支付金额小于退款金额
            pay_typ_refund_amount = pay_amount
        else:  # 支付金额大于退款金额
            pay_typ_refund_amount = refund_amount_dec
            refund_flag = True
        pay_method_typ = pay_log.get('pay_method_typ')
        # 余额和仓储卡需要更新用户资金
        if pay_method_typ == 2 or pay_method_typ == 3:
            if member_fund_update_counter > 0:
                db_member.update({'ver': db_member.get('ver') + member_fund_update_counter})
            member_fund_update_counter += 1
        refund_typ, err = handle_order_refund(cursor, db_member, return_order, pay_log, pay_typ_refund_amount)
        if err is not None:
            return None, err

        db = DB('cs_order_pay_logs', conn=cursor)
        update_data = {'return_amount': pay_typ_refund_amount, 'return_status': 1, 'tp_status': -2, 'updated': now}
        affected, err = db.update(update_data, {'id': pay_log_id})

        if err is not None:
            return None, err
        if affected == 0:
            return None, '更新退款记录失败'
        if return_order_id > 0:
            # 有单退货，添加退款支付记录
            new_pay_log = {
                'cashier_id': cashier_id,
                'order_id': return_order_id,
                'pay_method_typ': pay_method_typ,
                'pay_method': pay_log.get('pay_method'),
                'pay_typ_id': pay_log.get('pay_typ_id'),
                'pay_amount': pay_typ_refund_amount,
                'confirmed': now,
                'tp_order_sn': '',
                'tp_status': -2,
                'return_amount': 0,
                'return_status': 1,
                'created': now,
                'updated': now,
            }
            new_pay_log_id, _ = db.insert(new_pay_log)
            if new_pay_log_id == 0:
                return None, '保存退款记录失败'

        pay_log.update({'refund_typ': refund_typ, 'return_amount': pay_typ_refund_amount})
        pay_logs[i] = pay_log
        if refund_flag:
            break
        refund_amount_dec = refund_amount_dec - pay_amount
        if refund_amount_dec < 0:
            return None, '退款金额为负值'
        elif refund_amount_dec == Decimal('0'):
            break
    return pay_logs, err


def get_order_detail(cursor, order_id):
    order_detail = {}
    db = DB('cs_orders', conn=cursor)
    fields = ['id', 'shop_id', 'cashier_id', 'order_sn', 'pay_method',
              'member_id', 'account', 'goods_num', 'return_num', 'return_order_sn',
              'return_order_sn', 'total_price', 'remark', 'assoc_order_id', 'status',
              'created', 'deleted']
    db_order = db.one(fields, {'id': order_id})
    db_order_id = db_order.get('id', 0)
    if db_order_id == 0:
        return order_detail
    order_detail.update({'order': db_order})
    db_order_details = get_order_goods_list(cursor, order_id)
    order_detail.update({'order_detail': db_order_details})
    return order_detail


# 获取第三方订单 可以通过bill_num, order_sn查询订单
def get_third_party_order(field, val, cursor):
    # sql = 'SELECT co.order_sn, pl.pay_method_typ, pl.pay_typ_id, pl.tp_order_sn, pl.err
    # FROM `cs_orders` co
    # LEFT JOIN `cs_order_pay_logs` pl ON pl.`order_id` = co.id
    # WHERE co.`bill_num`=%s
    # AND pl.`pay_method_typ` = 100'
    db = DB('cs_orders', conn=cursor, table_as='co')
    left_join_tables = {
        'pl': {'table': 'cs_order_pay_logs', 'on': 'pl.order_id=co.id'}
    }
    left_join_fields = {
        'co': [('id', 'order_id'), 'order_sn', 'cart_typ', 'status'],
        'pl': [('id', 'pay_log_id'), 'pay_typ_id', 'tp_order_sn']
    }
    left_join_wheres = {
        'co': {field: val},
        'pl': {'pay_method_typ': 100}
    }
    return db.left_join(left_join_tables).one(left_join_fields, left_join_wheres)


# 获取订单支付状态
def is_third_party_order_sync_state(field, val):
    result_code = ''
    trade_state = ''
    if not (type(val) is str and len(val) > 0):
        return result_code, trade_state, '参数无效[order state]'
    cursor = connection.cursor()
    try:
        db_order = get_third_party_order(field, val, cursor)
        order_sn = db_order.get('order_sn', None)
        if order_sn is None:
            err = '订单不存在'
            return result_code, trade_state, err

        result_code, trade_state, err = sync_third_party_payment_order(db_order, cursor)
        # if tp_order_sn == '':
        #
        # else:
        #     db = DB('cs_orders', conn=cursor)
        #     db.update({'status': 1}, {'id': order_id, 'status': -3})

    except Exception as e:
        print(e)
        err = '获取支付状态异常'
    finally:
        cursor.close()
    return result_code, trade_state, err


# 更新第三方订单
def save_third_party_order(order_id, pay_log_id, tp_order_data, trade_state_desc, cursor):
    tp_status = tp_order_data.get('tp_status', 0)
    if tp_status == -1:
        db = DB('cs_orders', conn=cursor)
        db.update({'status': -3, 'trade_state_desc': trade_state_desc}, {'id': order_id})
    elif tp_status == -2:
        db = DB('cs_orders', conn=cursor)
        db.update({'status': -4, 'trade_state_desc': trade_state_desc}, {'id': order_id})
    db = DB('cs_order_pay_logs', conn=cursor)
    return db.update(tp_order_data, {
        'id': pay_log_id
    })


# 同步第三方支付订单状态
# result_code = 'SUCCESS'、'FAIL'、''(未知)
def sync_third_party_payment_order(cs_order_data, cursor):
    err = None
    update_data = {}
    result_code = ''
    order_sn = cs_order_data.get('order_sn', None)
    if order_sn is None:
        return 'FAIL', '订单不存在'
    order_id = cs_order_data.get('order_id')
    order_cart_typ = cs_order_data.get('cart_typ')
    order_status = cs_order_data.get('status')
    pay_log_id = cs_order_data.get('pay_log_id', None)
    tp_order_sn = cs_order_data.get('tp_order_sn', None)
    if pay_log_id is None or tp_order_sn is None:
        err = '支付记录不存在'  # 不应出现，出现说明订单不完整
        return result_code, err
    # if order_status == -3:  # 订单支付失败
    pay_typ_id = cs_order_data.get('pay_typ_id')
    trade_state = ''
    trade_state_desc = ''
    if pay_typ_id == 1:  # 微信
        traded_no, trade_state, tp_resp, tp_err = WxPay().queryOrder(order_sn)
        if tp_err is None:
            if trade_state == 'SUCCESS':
                result_code = 'SUCCESS'
                update_data.update({
                    'tp_order_sn': traded_no,
                    'tp_status': 1,
                    'tp_order_detail': json.dumps(tp_resp)
                })
            else:
                result_code = 'FAIL'
                update_data.update({
                    'tp_status': -1,
                    'tp_order_sn': traded_no,
                    'tp_order_detail': json.dumps(tp_resp),
                    'err': '支付状态未处理'
                })
            trade_state_desc = tp_resp.get('trade_state_desc', '')
        else:
            update_data.update({'err': tp_err})
    elif pay_typ_id == 2:  # 支付宝
        traded_no, trade_state, tp_resp, tp_err = Ali().queryOrder(order_sn)
        if tp_err is None:
            trade_state_desc = tp_resp.get('sub_msg', '')
            if trade_state == 'TRADE_SUCCESS':
                result_code = 'SUCCESS'
                update_data.update({
                    'tp_order_sn': traded_no,
                    'tp_status': 1,
                    'tp_order_detail': json.dumps(tp_resp)
                })
            elif trade_state == 'TRADE_CLOSED':
                result_code = 'FAIL'
                update_data.update({
                    'tp_order_sn': traded_no,
                    'tp_status': -1,
                    'tp_order_detail': json.dumps(tp_resp)
                })
            elif trade_state == 'TRADE_FINISHED':
                result_code = 'SUCCESS'
                update_data.update({
                    'tp_order_sn': traded_no,
                    'tp_status': 1,
                    'tp_order_detail': json.dumps(tp_resp)
                })
            elif trade_state == 'WAIT_BUYER_PAY':
                trade_state = 'USERPAYING'  # 统一支付状态
                update_data.update({
                    'tp_order_sn': traded_no,
                    'tp_order_detail': json.dumps(tp_resp),
                    'err': '等待买家付款'
                })
            else:
                update_data.update({
                    'tp_order_sn': traded_no,
                    'tp_order_detail': json.dumps(tp_resp),
                    'err': '支付状态未处理'
                })
        else:
            update_data.update({'err': tp_err})
    else:
        result_code = 'FAIL'
        update_data.update({'err': '无效的支付方式'})
    try:
        new_order_status = 1
        new_app_order_state = 7
        if order_cart_typ in [1, 2, 3]:
            new_order_status = -5
            new_app_order_state = 11
        if order_status in [0, -3]:
            if result_code == 'FAIL':
                # 明确失败，需要退回库存
                with transaction.atomic():
                    affected, err = save_third_party_order(order_id, pay_log_id, update_data, trade_state_desc, cursor)
                    if err is None:
                        if affected == 0:
                            err = '支付状态保存失败'
                        else:
                            recover_stock_from_order(cursor, order_id)
            elif result_code == 'SUCCESS':
                db = DB('cs_orders', conn=cursor)
                db.update({'status': new_order_status, 'trade_state_desc': ''}, {'id': order_id})

                db = DB('cs_order_pay_logs', conn=cursor)
                db.update(update_data, {
                    'id': pay_log_id
                })

                pay_time = time_helper.ts_to_time_str(time_format="%Y-%m-%d %H:%M:%S")
                filters = {'state': 0}
                app_order.update_order_status(cursor, order_id, new_app_order_state, {'pay_time': pay_time}, filters)
        elif order_status == 1:
            # 如果 cs_order 表的订单状态为已结，更新app_order未支付状态
            pay_time = time_helper.ts_to_time_str(time_format="%Y-%m-%d %H:%M:%S")
            filters = {'state': 0}
            app_order.update_order_status(cursor, order_id, new_app_order_state, {'pay_time': pay_time}, filters)
    except Exception as e:
        err = '更新第三方支付状态异常'
        print(err, e)
    return result_code, trade_state, err


# 从订单中恢复库存
def recover_stock_from_order(cursor, order_id, stock_typ=10):
    err = None
    db = DB('cs_order_details', conn=cursor)
    fields = ['id', 'goods_id', 'amount', 'selling_price', 'return_num', 'stock_log_id', 'status']
    db_order_details = db.find(fields, {'order_id': order_id, 'goods_id>0': None})
    stock_log_dh = DB('cs_stock_logs', conn=cursor)
    gdb = DB('table_goods', conn=cursor)
    cs_order_dh = DB('cs_orders', conn=cursor)
    db_order = cs_order_dh.one(['shop_id', 'cashier_id', 'status'], {'id': order_id})
    shop_id = db_order.get('shop_id')
    cashier_id = db_order.get('cashier_id')
    # 只恢复线上支付未结状态的订单
    now = get_ts()
    try:
        for order_detail in db_order_details:
            stock_log_id = order_detail.get('stock_log_id')
            if stock_log_id == 0:
                order_detail_id = order_detail.get('id')
                goods_id = order_detail.get('goods_id')
                amount = order_detail.get('amount')
                return_num = order_detail.get('return_num')
                selling_price = order_detail.get('selling_price')
                recover_num_dec = amount - return_num
                if recover_num_dec > 0:
                    goods_fields = ['id', 'scount', 'sell_count', 'ver']
                    db_goods = gdb.one(goods_fields, {
                        'id': goods_id
                    })
                    if db_goods.get('id', 0) > 0:
                        stock_prev = db_goods.get('scount')
                        stock_next = stock_prev + recover_num_dec
                        sell_count_next = db_goods.get('sell_count') - recover_num_dec
                        goods_ver = db_goods.get('ver')
                        goods_ver_next = goods_ver + 1
                        stock_log_data = {
                            'stock_order_id': order_id,
                            'stock_typ': stock_typ,
                            'goods_id': goods_id,
                            'shop_id': shop_id,
                            'cashier_id': cashier_id,
                            'cash_device_code': '',
                            'cost_price': selling_price,
                            'amount': recover_num_dec,
                            'amount_prev': stock_prev,
                            'amount_next': stock_next,
                            'created': now,
                        }
                        stock_log_id, _ = stock_log_dh.insert(stock_log_data)
                        if stock_log_id == 0:
                            raise MyException('库存变动保存失败')
                        affected = gdb.update({
                            'scount': stock_next,
                            'sell_count': sell_count_next,
                            'ver': goods_ver_next,
                        }, {
                            'id': goods_id,
                            'ver': goods_ver
                        })
                        if affected == 0:
                            raise MyException('更新商品库存失败')
                        affected = db.update({'stock_log_id': stock_log_id}, {'id': order_detail_id})
                        if affected == 0:
                            raise MyException('订单明细状态更新失败')
        if stock_typ == 10:
            affected = cs_order_dh.update({'status': -3}, {'id': order_id})
            if affected == 0:
                raise MyException('订单状态更新失败')
    except MyException as e:
        err = str(e)
    except Exception as e:
        err = '恢复库存异常'
        print(err, e)
    return err


def sort_pay_methods(pay_methods):
    # 收款优先级 线下扫码\现金->仓储卡->余额->微信\支付宝
    sort_arr = [1, 10, 2, 3, 200,100]
    sorted_pay_methods = []
    for si in sort_arr:
        for pay_method in pay_methods:
            typ = int(pay_method.get('typ'))
            if typ == si:
                sorted_pay_methods.append(pay_method)
    return sorted_pay_methods


def query_third_party_order_pay_data(order_sn, cursor):
    sql = 'SELECT co.id order_id,pl.id pay_log_id,pl.`pay_typ_id`,pl.`pay_amount`,pl.tp_status' \
          ' FROM `cs_orders` co' \
          ' LEFT JOIN `cs_order_pay_logs` pl ON pl.`order_id`=co.id' \
          ' WHERE pl.`pay_method_typ`=100 AND co.order_sn=%s'
    cursor.execute(sql, [order_sn])
    row = cursor.fetchone()
    data = {}
    if row is not None:
        fields = ['order_id', 'pay_log_id', 'pay_typ_id', 'pay_amount', 'tp_status']
        for i, field in enumerate(fields):
            data[field] = row[i]
    return data


def query_third_party_order_pay_state(order_sn, cursor):
    sql = 'SELECT co.id order_id,pl.pay_method,pl.pay_typ_id,pl.tp_order_sn,pl.tp_status,pl.tp_order_detail' \
          ' FROM `cs_orders` co' \
          ' LEFT JOIN `cs_order_pay_logs` pl ON pl.`order_id`=co.id' \
          ' WHERE pl.`pay_method_typ`=100 AND co.order_sn=%s'
    cursor.execute(sql, [order_sn])
    row = cursor.fetchone()
    data = {}
    if row is not None:
        fields = ['order_id', 'pay_method', 'pay_typ_id', 'tp_order_sn', 'tp_status', 'tp_order_detail']
        for i, field in enumerate(fields):
            data[field] = row[i]
    return data


# 将购物车保存到订单表
def save_cart_to_order_v2(cashier_id, app_order_base_data, cart_goods_group, order_base_data, cursor):
    now = get_ts()
    cart_goods_arr = cart_goods_group.get('arr')
    order_total_price_dec = order_base_data.get('total_price')
    order_cart_total_price_dec = cart_goods_group.get('cart_total_price')
    order_goods_num = cart_goods_group.get('num')
    order_goods_num_pos = abs(order_goods_num)
    order_data = {
        'goods_num': order_goods_num_pos,
        'cart_total_price': order_cart_total_price_dec,
        'created': now,
        'updated': now,
    }
    order_detail_arr = []
    order_data.update(order_base_data)
    shop_id = order_base_data.get('shop_id')
    order_sn = order_base_data.get('order_sn')
    total_price_dec = order_base_data.get('total_price')
    db = DB('cs_orders', conn=cursor)
    cs_order_id, _ = db.insert(order_data)
    if cs_order_id == 0:
        return order_data, order_detail_arr, '订单保存失败'
    order_data.update({'id': cs_order_id})
    datetime_str = time_helper.ts_to_time_str(now, time_format='%Y-%m-%d %H:%M:%S')
    app_shop_name = app_order_base_data.get('shoper_name')
    app_member_id = app_order_base_data.get('member_id')
    app_order_data = {
        'order_id': order_sn,
        'order_time': datetime_str,
        'total': order_total_price_dec,
        'pay_usdt': order_total_price_dec,
        'offline_order_id': order_sn,
        'cs_order_id': cs_order_id,
        'is_mixed_pay': 0,
        'stats_total_price': 0,
        'pay_mode': 4,
        'only_pay_no': '现金支付',
        'send_shop_id': shop_id
    }
    app_order_data.update(app_order_base_data)
    app_order_id, err = app_order.save_app_order(cursor, app_order_data)
    if err is not None:
        return err
    for cart_goods in cart_goods_arr:
        selling_price = cart_goods.get('selling_price')
        goods_id = cart_goods.get('goods_id')
        amount_dec = cart_goods.get('amount')
        amount_pos = abs(amount_dec)
        cart_typ = cart_goods.get('cart_typ')
        if cart_typ == 1:
            status = -4
            stock_typ = 20
        elif cart_typ == 2:
            status = -5
            stock_typ = 21
        else:
            return order_data, order_detail_arr, '无效的订单类型'
        amount_prev = Decimal('0')
        amount_next = Decimal('0')
        if goods_id > 0:
            goods_fields = ['id', 'scount', 'sell_count', 'ver']
            db_goods = goods.get_goods_by_id(cursor, shop_id, goods_id, goods_fields)
            if db_goods.get('id', 0) > 0:
                db_sell_count = db_goods.get('sell_count')
                new_sell_count = db_sell_count + amount_dec
                amount_prev = db_goods.get('scount')
                amount_next = amount_prev - amount_dec
                db = DB('cs_stock_logs', conn=cursor)
                stock_log_data = {
                    'stock_order_id': cs_order_id,
                    'stock_typ': stock_typ,
                    'goods_id': goods_id,
                    'shop_id': shop_id,
                    'cashier_id': cashier_id,
                    'cost_price': 0,
                    'amount': amount_pos,
                    'amount_prev': amount_prev,
                    'amount_next': amount_next,
                    'created': now,
                }
                affected, _ = db.insert(stock_log_data)
                if affected == 0:
                    return order_data, order_detail_arr, '保存商品库存变更失败'

                ver = db_goods.get('ver')
                next_ver = ver + 1
                new_goods_data = {
                    'scount': amount_next,
                    'sell_count': new_sell_count,
                    'ver': next_ver
                }
                db = DB('table_goods', conn=cursor)
                affected, _ = db.update(new_goods_data, 'id=%s', [goods_id])
                if affected == 0:
                    return order_data, order_detail_arr, '更新商品库存失败'
        goods_name = cart_goods.get('goods_name')
        is_discount = cart_goods.get('is_discount')
        subtotal = cart_goods.get('subtotal')
        subtotal_pos = abs(subtotal)
        subtotal_raw_pos = abs(selling_price * amount_dec)
        order_detail_data = {
            'order_id': cs_order_id,
            'goods_id': goods_id,
            'goods_name': goods_name,
            'barcode': cart_goods.get('barcode'),
            'amount': amount_pos,
            'selling_price': selling_price,
            'spec_typ': cart_goods.get('spec_typ'),
            'is_input_price': cart_goods.get('is_input_price'),
            'is_discount': cart_goods.get('is_discount'),
            'subtotal_raw': subtotal_raw_pos,
            'subtotal': subtotal_pos,
            'stock_prev': amount_prev,
            'stock_next': amount_next,
            'status': status,
            'created': now,
            'updated': now
        }
        db = DB('cs_order_details', conn=cursor)
        order_detail_id, _ = db.insert(order_detail_data)
        if order_detail_id == 0:
            return order_data, order_detail_arr, '保存订单明细失败'
        stats_price_dec = Decimal(0)
        if order_total_price_dec > 0:
            stats_price_dec = (subtotal_pos / order_total_price_dec).quantize(Decimal('0.00'))
        app_order_detail_data = {
            'member_id': app_member_id,
            'shoper_name': app_shop_name,
            'order_id': order_sn,
            'goods_id': goods_id,
            'goods_name': goods_name,
            'goods_price': selling_price,
            'order_time': datetime_str,
            'ratio': 0,
            'sell_number': amount_pos,
            'is_discount_goods': is_discount,
            'sell_price': subtotal_pos,
            'stats_price': stats_price_dec,
            'pay_mode': 4,
            'pay_usdt': subtotal_pos,
            'only_pay_no': '现金支付',
            'send_shop_id': shop_id,
        }
        app_order_detail_id, _ = app_order.save_app_order_detail(cursor, app_order_detail_data)
        if app_order_detail_id == 0:
            return order_data, order_detail_arr, '保存订单明细失败'
        order_detail_arr.append(order_detail_data)
    if total_price_dec != 0:
        order_pay_log = {
            'cashier_id': cashier_id,
            'order_id': cs_order_id,
            'pay_method_typ': 1,
            'pay_method': '现金',
            'pay_typ_id': 0,
            'pay_amount': total_price_dec,
            'confirmed': now,
            'return_status': 1
        }
        log_id, _ = save_order_pay_log(order_pay_log, cursor)
        if log_id == 0:
            return order_data, order_detail_arr, '保存支付记录失败'
    return order_data, order_detail_arr, err


# 将购物车保存到订单表
def save_cart_to_order_v3(cashier_id, app_order_base_data, cart_goods_group, order_base_data, cursor):
    now = get_ts()
    cart_goods_arr = cart_goods_group.get('arr')
    order_total_price_dec = order_base_data.get('total_price')
    order_cart_total_price_dec = cart_goods_group.get('cart_total_price')
    order_goods_num = cart_goods_group.get('num')
    order_goods_num_pos = abs(order_goods_num)
    order_data = {
        'goods_num': order_goods_num_pos,
        'cart_total_price': order_cart_total_price_dec,
        'created': now,
        'updated': now,
    }
    order_detail_arr = []
    order_data.update(order_base_data)
    shop_id = order_base_data.get('shop_id')
    order_sn = order_base_data.get('order_sn')
    db = DB('cs_orders', conn=cursor)
    cs_order_id, _ = db.insert(order_data)
    if cs_order_id == 0:
        return order_data, order_detail_arr, '订单保存失败'
    order_data.update({'id': cs_order_id})
    datetime_str = time_helper.ts_to_time_str(now, time_format='%Y-%m-%d %H:%M:%S')
    app_shop_name = app_order_base_data.get('shoper_name')
    app_member_id = app_order_base_data.get('member_id')
    app_order_data = {
        'order_id': order_sn,
        'order_time': datetime_str,
        'total': order_total_price_dec,
        'pay_usdt': order_total_price_dec,
        'offline_order_id': order_sn,
        'cs_order_id': cs_order_id,
        'is_mixed_pay': 0,
        'stats_total_price': 0,
        'pay_mode': 4,
        'only_pay_no': '现金支付',
        'send_shop_id': shop_id
    }
    app_order_data.update(app_order_base_data)
    app_pay_mode = app_order_data.get('pay_mode')
    if app_pay_mode not in [2, 3]:
        app_order_data.update({'pay_time': datetime_str})
    app_order_id, err = app_order.save_app_order(cursor, app_order_data)
    if err is not None:
        return err
    for cart_goods in cart_goods_arr:
        selling_price = cart_goods.get('selling_price')
        goods_id = cart_goods.get('goods_id')
        amount_dec = cart_goods.get('amount')
        amount_pos = abs(amount_dec)
        cart_typ = cart_goods.get('cart_typ')
        if cart_typ == 1:
            status = -4
            stock_typ = 20
        elif cart_typ == 2:
            status = -5
            stock_typ = 21
        else:
            return order_data, order_detail_arr, '无效的订单类型'
        amount_prev = Decimal('0')
        amount_next = Decimal('0')
        if goods_id > 0:
            goods_fields = ['id', 'scount', 'sell_count', 'ver']
            db_goods = goods.get_goods_by_id(cursor, shop_id, goods_id, goods_fields)
            if db_goods.get('id', 0) > 0:
                db_sell_count = db_goods.get('sell_count')
                new_sell_count = db_sell_count + amount_dec
                amount_prev = db_goods.get('scount')
                amount_next = amount_prev - amount_dec
                db = DB('cs_stock_logs', conn=cursor)
                stock_log_data = {
                    'stock_order_id': cs_order_id,
                    'stock_typ': stock_typ,
                    'goods_id': goods_id,
                    'shop_id': shop_id,
                    'cashier_id': cashier_id,
                    'cost_price': 0,
                    'amount': amount_pos,
                    'amount_prev': amount_prev,
                    'amount_next': amount_next,
                    'created': now,
                }
                affected, _ = db.insert(stock_log_data)
                if affected == 0:
                    return order_data, order_detail_arr, '保存商品库存变更失败'

                ver = db_goods.get('ver')
                next_ver = ver + 1
                new_goods_data = {
                    'scount': amount_next,
                    'sell_count': new_sell_count,
                    'ver': next_ver
                }
                db = DB('table_goods', conn=cursor)
                affected, _ = db.update(new_goods_data, 'id=%s', [goods_id])
                if affected == 0:
                    return order_data, order_detail_arr, '更新商品库存失败'
        goods_name = cart_goods.get('goods_name')
        is_discount = cart_goods.get('is_discount')
        subtotal = cart_goods.get('subtotal')
        subtotal_pos = abs(subtotal)
        subtotal_raw_pos = selling_price * amount_dec
        order_detail_data = {
            'order_id': cs_order_id,
            'goods_id': goods_id,
            'goods_name': goods_name,
            'barcode': cart_goods.get('barcode'),
            'amount': amount_pos,
            'selling_price': selling_price,
            'spec_typ': cart_goods.get('spec_typ'),
            'is_input_price': cart_goods.get('is_input_price'),
            'is_discount': cart_goods.get('is_discount'),
            'subtotal_raw': subtotal_raw_pos,
            'subtotal': subtotal_pos,
            'stock_prev': amount_prev,
            'stock_next': amount_next,
            'status': status,
            'created': now,
            'updated': now
        }
        db = DB('cs_order_details', conn=cursor)
        order_detail_id, _ = db.insert(order_detail_data)
        if order_detail_id == 0:
            return order_data, order_detail_arr, '保存订单明细失败'
        stats_price_dec = Decimal(0)
        if order_total_price_dec > 0:
            stats_price_dec = (subtotal_pos / order_total_price_dec).quantize(Decimal('0.00'))
        app_order_detail_data = {
            'member_id': app_member_id,
            'shoper_name': app_shop_name,
            'order_id': order_sn,
            'goods_id': goods_id,
            'goods_name': goods_name,
            'goods_price': selling_price,
            'order_time': datetime_str,
            'ratio': 0,
            'sell_number': amount_pos,
            'is_discount_goods': is_discount,
            'sell_price': subtotal_pos,
            'stats_price': stats_price_dec,
            'pay_mode': app_pay_mode,
            'pay_usdt': subtotal_pos,
            'only_pay_no': '现金支付',
            'send_shop_id': shop_id,
        }
        if app_pay_mode not in [2, 3]:
            app_order_detail_data.update({'pay_time': datetime_str})
        app_order_detail_id, _ = app_order.save_app_order_detail(cursor, app_order_detail_data)
        if app_order_detail_id == 0:
            return order_data, order_detail_arr, '保存订单明细失败'
        order_detail_arr.append(order_detail_data)
    return order_data, order_detail_arr, err


def update_coupon_status(cashier_id, account, cs_order_id):
    api_err = app_api.app_goods_exchange_coupon(cashier_id, account, cs_order_id)
    if api_err is None:
        coupon_status = 1
    else:
        coupon_status = -1
    db = DB('cs_orders')
    db.update({'coupon_status': coupon_status}, {'id': cs_order_id})


def update_order_del_ts(order_id, cursor):
    now = common.get_ts()
    db = DB('cs_orders', conn=cursor)
    return db.update({'deleted': now}, {'id': order_id})


def mark_invalid_order(cs_order_id, app_order_id, status):
    now = common.get_ts()
    try:
        if cs_order_id != 0 and app_order_id != 0:
            with connection.cursor() as cursor:
                if cs_order_id != 0:
                    dh_cs_order = DB('cs_orders', conn=cursor)
                    dh_cs_order.update({'status': status, 'deleted': now}, {'id': cs_order_id})
                if app_order_id != 0:
                    dh_app_main_order = DB('table_main_orders', conn=cursor)
                    dh_app_main_order.delete({'id': app_order_id})
    except Exception as e:
        common.logger(e)
        pass
